#include "parse.h"
#include "simulate.h"
#include "alg.h"
#include "timing.h"
#include "place.h"
#include "node.h"
#include <sstream>

//#ifndef ONERANK
//#define ONERANK
//#endif

//#ifndef WRITEPROB
//#define WRITEPROB
//#endif

Circuit *C;
int MC_NUM;
vector<int> sim_vals;
extern bool formHybrid();

double criteria = 0.7;
int	main(int argc, char **argv)
{
	char *filename, *placename;
	int seed1,seed2,trace_size;
	cout<<"parsing file............."<<endl;
	if (argc < 5) {
		cerr << "Usage: " << argv[0] << " bench file" << " trace size" << " seed1 seed2" <<endl;
		return 2;
	}
	else if (argc == 5) {
		filename = argv[1];
		trace_size = atoi(argv[2]);
		seed1 = atoi(argv[3]);
		seed2 = atoi(argv[4]);
	}
	parse(filename);
        
        if(trace_size == 0)
        {
                cout<<"Cannot select nothing! Try again..."<<endl;
                exit(0);
        }
        
        for(int i=0; i<C->signalSize(); ++i)
                C->getSignal(i)->setIndex(i);
        
	for(int i=0; i<C->gateSize(); ++i)
                C->getGate(i)->setGateIndex(i);
        
        //	cout<<"timing ................"<<endl;
	//	timing = new Timing ();
	//	timing->MarkCriticalFF (0.2);
	//	timing->CountCriticalPathFF (0.2);
	//	timing->CountCriticalPathFF (k);
	
        cout<<"placement"<<endl;
        Place *pl = new Place(C);
        /*
	pl->partition(placename,m,p);
        for(int k=0; k<pl->regs.size(); ++k){
		int rf=0;

		for(int i=0; i<C->flipflopSize(); ++i){
			//cout<<C->getFlipflop(i)->getOutput(0)->x<<','<<C->getFlipflop(i)->getOutput(0)->y<<endl;
			if(C->getFlipflop(i)->getOutput(0)->region == k)
				++rf;
		}
		pl->regs[k].ff = rf;
		cout<<"region "<<k<<": "<<rf<<endl;
	}
        */

	Algorithm *alg = new Algorithm(C, pl, 0);
	
	cout<<"probablity computation......"<<endl;
	Simulate *sim = new Simulate(C);
	string tmp1 = filename;
	tmp1 += ".prob";
#ifdef WRITEPROB
	cout<<"writing probability file..............."<<endl;
        MC_NUM = 100000;
        //sim->initSimulate();
        //sim->sim1cycle();
        sim->forwardSimReg(1);
        for(int i=0; i<C->signalSize(); ++i)
                sim_vals.push_back(C->getSignal(i)->getVal());
        sim->forwardSim_event(MC_NUM);
        C->write_prob(&tmp1[0]);
#else
        clock_t start1, finish1, start2, finish2;
	//finding suspicious nodes first
        start1 = clock();
        cout<<"first round simulation for suspicious gates starts......"<<endl;
        MC_NUM = seed1;
        sim->forwardSimReg(MC_NUM);
	
        cout<<"forming hybrid gates......"<<endl;
	formHybrid();

	//accumulate event simualtion results for hybrid nodes
        cout<<"second round simulation for HG event prob starts......"<<endl;
        sim_vals.clear();
        MC_NUM = seed2;
        sim->forwardSimReg(1);
        //sim->initSimulate(true);
        //sim->sim1cycle();
        for(int i=0; i<C->signalSize(); ++i)
                sim_vals.push_back(C->getSignal(i)->getVal());
        sim->forwardSim_event(MC_NUM);
        finish1 = clock();
        
        //C->dumpHgates();
        //C->dumpHgatesToFile();
        C->read_prob(&tmp1[0]);
	int cnt=0;
	vector<Signal*> traces;
	
	/*
          alg->test_r = true;
	  for(int i=0; i<pl->regs.size(); ++i){
		if(pl->regs[i].ff == 0)
			continue;
		alg->r=i;
		alg->traceSelect(1);
		traces.push_back(alg->getTraced(0));
	}
	cout<<traces.size()<<endl;
	for(int i=0; i<traces.size(); ++i){
		//cout<<traces[i]->getName()<<" "<<traces[i]->region<<endl;
		if(traces[i]->getInput(0)->signature() == FLIPFLOP){
			traces[i]->getInput(0)->isCriticalFF = true;
			traces[i]->getInput(0)->cPathCount = 1;
		}
		else{
			traces[i]->getInput(1)->isCriticalFF = true;
			traces[i]->getInput(1)->cPathCount = 1;	
			}
	}
	
		C->noCff=0;
		for(int i=0; i<C->flipflopSize(); ++i)
			if(C->getFlipflop(i)->isCriticalFF){
				++C->noCff;
				C->criticalFFs.push_back(C->getFlipflop(i));
			}
	
                alg->computeForwardPathWeight();
                alg->computeBackwardPathWeight();
        */
#ifndef ONERANK
        alg->test_r = false;
        cout<<"selecting trace signals............."<<endl;
	cout<<"trace size is "<<trace_size<<endl;
        
	start2 = clock();
	alg->traceSelect(trace_size);
	finish2 = clock();
        
        alg->printTraces();
#endif
	int vcn=0;	
	//for(int i=0;i<C->flipflopSize();++i)
        //if(C->getFlipflop(i)->isCriticalFF)
        //++vcn;
	//cout<<"FF"<<C->getFlipflop(i)->getIndex()<<":"<<C->getFlipflop(i)->getOutput(0)->getV()<<endl;
	//cout<<"# of critical FFs:"<<vcn<<endl;
	
	//cout<<"total visibility:"<<alg->getTV()<<endl;
	//cout<<"critical visibility:"<<alg->TVC<<endl;
        cout<<"total number of flipflops is "<<C->flipflopSize()<<endl;
        cout<<"total number of gates is "<<C->gateSize()<<endl;
        cout<<"total number of HGates is "<<C->hgateSize()<<endl;
        int count=0;
        for(int i = 0; i < C->hgateSize(); i++)
                count += ((HybridNode*)(C->getHGate(i)))->getIndexSize();
        cout<<"total number of HGates covered is "<<count<<endl;
        cout<<"non critical visibility:"<<alg->TVNC<<endl;
        cout<<"total runtime for first part is: "<<( (finish1 - start1)/CLOCKS_PER_SEC )<<endl;
        cout<<"total runtime for second part is: "<<( (finish2 - start2)/CLOCKS_PER_SEC )<<endl;
        
#ifdef ONERANK
        string tmp = filename;
	tmp += '.';
	tmp += argv[2];
	tmp += ".3.dump";
        cout<<tmp<<endl;
        
        MC_NUM = 200;
        Confset* C1 = new Confset;
        //alg->initGates();
        for(int i=0; i<C->flipflopSize(); ++i)
        {
                Conf* c1 = new Conf;
                //alg->clearTrace();
                //alg->addTraced(C->getFlipflop(i)->getOutput(0));
                sim->clearTraced();
                sim->addTraced(C->getFlipflop(i)->getOutput(0));
                c1->tracedSigs.push_back(C->getFlipflop(i)->getOutput(0));
                c1->tracedSigs[0]->setTraced(true);
                c1->TV = sim->computVN();
                c1->TVNC = c1->TV;
                C1->confs.push_back(c1);
                c1->tracedSigs[0]->setTraced(false);
        }
        
        cout<<"test for single DFF ends....."<<endl;
        
        C1->rank();
        //looking at the top k ones
        ofstream out("Rank_List_mimi");
        out<<"Rank List Starts...."<<endl;
        for(int i=0; i<C1->confs.size(); ++i){
                out<<"signal size"<<C1->confs[i]->tracedSigs.size()<<"\t";
                out<<"Signal Index: "<<C1->confs[i]->tracedSigs[0]->getIndex()<<"\t";
                out<<"TV: "<<C1->confs[i]->TV<<"\t";
                out<<"TVNC: "<<C1->confs[i]->TVNC<<endl;
        }
#else        
        
	string tmp = filename;
	tmp += '.';
	tmp += argv[2];
	tmp += ".2.dump";
        
        string ts = filename;
        stringstream ss;
        ss << alg->tracedSize();
        ts += "_";
        ts += ss.str();
        ts += ".DFF";
        
        alg->initGates();
        ofstream out(ts.c_str());
        cout<<"Check here!!! Selected signals...."<<endl;
        out<<alg->tracedSize()<<"\t";
        for(int i=0; i<alg->tracedSize(); ++i)
        {
                //cout<<alg->getTraced(i)->getName()<<endl;
                cout<<alg->getTraced(i)->getIndex()<<"\t";
                out<<alg->getTraced(i)->getIndex()<<"\t";
                sim->addTraced(alg->getTraced(i));
        }
        cout<<endl;
        out<<endl;
        
        MC_NUM = 200;
        //for(int i=0; i<C->signalSize(); ++i)
        //cout <<"Signal name " << C->getSignal(i)->getName() << " is Traced? "<< 
        //C->getSignal(i)->getTraced() << endl;
        
	//cout<<"# VN:"<<sim->computVN(&tmp[0])<<endl;
        cout<<"# VN:"<<sim->computVN()<<endl;
#endif
#endif  
        /*
        vector<int> sw1, sw2;
       	for(int i=0; i<pl->regs.size(); ++i)
		pl->regs[i].sw = 0;
	for(int i=0; i<C->gateSize(); ++i){
		if((C->getGate(i)->getOutput(0)->region < 0) || (C->getGate(i)->getOutput(0)->region>pl->regs.size()))
			continue;
		pl->regs[C->getGate(i)->getOutput(0)->region].sw +=C->getGate(i)->getOutput(0)->sw;
	}
	for(int i=0; i<pl->regs.size(); ++i)
		sw1.push_back(pl->regs[i].sw);
	for(int i=0; i<pl->regs.size(); ++i)
		pl->regs[i].sw = 0;
	for(int i=0; i<C->gateSize(); ++i){
		if((C->getGate(i)->getOutput(0)->region < 0) || (C->getGate(i)->getOutput(0)->region>pl->regs.size()))
			continue;
		pl->regs[C->getGate(i)->getOutput(0)->region].sw +=C->getGate(i)->getOutput(0)->sw1;
	}
	for(int i=0; i<pl->regs.size(); ++i)
		sw2.push_back(pl->regs[i].sw);
      	float err=0;
	for(int i=0; i<pl->regs.size(); ++i)
		err += abs(sw1[i]-sw2[i])/((float)sw1[i]);
	cout<<"error:" << err/sw1.size()<<endl;
        */			
	return 0;
}
